package com.cnunicom.modules.tra.service.impl;

import com.baomidou.mybatisplus.core.conditions.interfaces.Compare;
import com.cnunicom.common.utils.DateUtils;
import com.cnunicom.modules.tra.entity.MemberEntity;
import com.cnunicom.modules.tra.entity.RecordEntity;
import com.cnunicom.modules.tra.service.HomeService;
import com.cnunicom.modules.tra.service.MemberService;
import com.cnunicom.modules.tra.service.RecordService;
import com.cnunicom.modules.tra.vo.HomeVO;
import org.apache.commons.lang.StringUtils;
import org.apache.poi.hssf.record.crypto.Biff8DecryptingStream;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.Month;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @Author: dingziyuan
 * @Date: 2020/1/29/029 21:54
 * @Description: *
 */
@Service("HomeService")
public class HomeServiceImpl implements HomeService {

    @Autowired
    private RecordService recordService;
    @Autowired
    private MemberService memberService;
    @Resource
    private HashOperations<String, String, String> hashOperations;


    @Override
    public HomeVO list() {

        HomeVO vo = new HomeVO();
        //总销售额
        vo.setTotalSales(typeConversion(hashOperations.get("sales", "totalSales")));
        //月销售额
        vo.setMonthlySales(typeConversion(hashOperations.get("sales", "monSales")));
        //日销售额
        vo.setDailySales(typeConversion(hashOperations.get("sales", "daySales")));
        //周同比
        vo.setWeekRatio(typeConversion(hashOperations.get("sales", "weekRatio")));
        //日同比
        vo.setDayRatio(typeConversion(hashOperations.get("sales", "dayRatio")));
        //日均销售额
        vo.setAverageSales(typeConversion(hashOperations.get("sales", "averageSales")));
        //总会员数
        vo.setTotalMembers(typeConversion(hashOperations.get("member", "totalMembers")));
        //周同比
        vo.setDivideOfWeek(typeConversion(hashOperations.get("member", "divideOfWeek")));
        //日同比
        vo.setDivideOfDay(typeConversion(hashOperations.get("member", "divideOfDay")));
        //日均注册会员数
        vo.setAverageMember(typeConversion(hashOperations.get("member", "averageMember")));

        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DateUtils.DATE_PATTERN);
        LocalDate now = LocalDate.now();
        String today = now.format(formatter);
        String sevenDaysAgo = now.plusDays(-7).format(formatter);

        ArrayList<String> period = new ArrayList<>();
        period.add(sevenDaysAgo);
        period.add(today);

        vo.setPeriod(period);
        chart(sevenDaysAgo,today,vo);
        return vo;
    }

    private BigDecimal typeConversion(String var) {
        if (StringUtils.isNotBlank(var)) {
            return BigDecimal.valueOf(Double.parseDouble(var));
        } else {
            return BigDecimal.valueOf(0L);
        }
    }

    @Override
    public HomeVO chart(String startDate, String endDate, HomeVO vo) {

        //日销售额集合
        List<RecordEntity> dailySalesList = recordService.query()
                .select("sum(price) daily_sales","date")
                .between("date",startDate,endDate)
                    .groupBy("date")
                .list();

        //日注册会员集合
        List<MemberEntity> dailyMemberList = memberService.query()
                .select("count(DISTINCT id) daily_members","CAST(create_time as date) create_time")
                .between("create_time", startDate, endDate)
                .groupBy("CAST(create_time as date)")
                .list();

        vo.setDailySalesList(dailySalesList);
        vo.setDailyMemberList(dailyMemberList);

        return vo;
    }


    /**
     * 每天晚上凌晨3点进行定时任务调取
     * 从记录表和会员表中获取展示数据放入redis中
      */
    @Override
    public void homeDataToRedis() {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        DateTimeFormatter formatterTime = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

        BigDecimal totalDays = BigDecimal.valueOf(recordService.query().select("DISTINCT date").count());
        salesHandle(formatter, totalDays);
        mebHandle(formatterTime, totalDays);
    }


    /**
     * 销售额处理
     *
     * @param dateTimeFormatter 时间转换
     * @param totalDays         总天数
     */
    private void salesHandle(DateTimeFormatter dateTimeFormatter, BigDecimal totalDays) {

        LocalDate now = LocalDate.now();
        int dayOfYear = now.plusDays(-1).getDayOfYear();
        Month month = now.getMonth();

        LocalDate thisWeekMonday = now.minusWeeks(1).with(DayOfWeek.MONDAY);
        LocalDate thisWeekSunday = now.minusWeeks(1).with(DayOfWeek.SUNDAY);
        LocalDate monday = now.minusWeeks(2).with(DayOfWeek.MONDAY);
        LocalDate sunday = now.minusWeeks(2).with(DayOfWeek.SUNDAY);

        List<RecordEntity> list = recordService.list();

        //总销售额
        BigDecimal totalSales = list.stream().map(RecordEntity::getPrice).reduce(BigDecimal::add)
                .orElse(BigDecimal.ZERO);

        //月销售额
        BigDecimal monthlySales = list.stream()
                .filter(item -> LocalDate.parse(item.getDate(), dateTimeFormatter).getMonth().equals(month))
                .map(RecordEntity::getPrice).reduce(BigDecimal::add).orElse(BigDecimal.ZERO);

        //日销售额(昨天的)
        BigDecimal dailySales = list.stream()
                .filter(item -> LocalDate.parse(item.getDate(), dateTimeFormatter).getDayOfYear() == dayOfYear)
                .map(RecordEntity::getPrice).reduce(BigDecimal::add).orElse(BigDecimal.ZERO);


        //上上周销售总额
        BigDecimal lastWeekPrice = list.stream().filter(item -> {
            LocalDate parse = LocalDate.parse(item.getDate(), dateTimeFormatter);
            return parse.isAfter(monday) && parse.isBefore(sunday);
        }).map(RecordEntity::getPrice).reduce(BigDecimal::add).orElse(BigDecimal.ZERO);

        //上周销售总额
        BigDecimal thisWeekPrice = list.stream().filter(item -> {
            LocalDate parse = LocalDate.parse(item.getDate(), dateTimeFormatter);
            return parse.isAfter(thisWeekMonday) && parse.isBefore(thisWeekSunday);
        }).map(RecordEntity::getPrice).reduce(BigDecimal::add).orElse(BigDecimal.ZERO);

        //周同比
        BigDecimal weekRatio = BigDecimal.valueOf(0L);
        if (lastWeekPrice.longValue() != 0L) {
            weekRatio = thisWeekPrice.subtract(lastWeekPrice)
                    .divide(lastWeekPrice, 2).multiply(BigDecimal.valueOf(100L));
        }

        //昨天的销售额
        BigDecimal today = list.stream().filter(item -> {
            LocalDate parse = LocalDate.parse(item.getDate(), dateTimeFormatter);
            return parse.getDayOfYear() == dayOfYear - 1;
        }).map(RecordEntity::getPrice).reduce(BigDecimal::add).orElse(BigDecimal.ZERO);

        //前天的销售额
        BigDecimal yesterday = list.stream().filter(item -> {
            LocalDate parse = LocalDate.parse(item.getDate(), dateTimeFormatter);
            return parse.getDayOfYear() == dayOfYear - 2;
        }).map(RecordEntity::getPrice).reduce(BigDecimal::add).orElse(BigDecimal.ZERO);

        //日同比
        BigDecimal dayRatio = BigDecimal.valueOf(0L);
        if (yesterday.longValue() != 0L) {
            dayRatio = today.subtract(yesterday)
                    .divide(yesterday, 2).multiply(BigDecimal.valueOf(100L));
        }


        BigDecimal divide = totalSales.divide(totalDays, 2);
        BigDecimal averageSales = divide == null || divide.equals(BigDecimal.ZERO) ? BigDecimal.ZERO : divide;

        /*
            存入redis
         */

        //总销售额
        Boolean totalIsAbsent = hashOperations.putIfAbsent("sales", "totalSales", totalSales.toString());
        if (totalIsAbsent.equals(Boolean.FALSE)) {
            hashOperations.put("sales", "totalSales", totalSales.toString());
        }

        //月销售额
        boolean monthlyIsAbsent = hashOperations.putIfAbsent("sales", "monSales", monthlySales.toString());
        if (monthlyIsAbsent == Boolean.FALSE) {
            hashOperations.put("sales", "monSales", monthlySales.toString());
        }

        //昨日销售额(实时增加,凌晨置空)
        Boolean dailyIsAbsent = hashOperations.putIfAbsent("sales", "daySales", "0");
        if (dailyIsAbsent.equals(Boolean.FALSE)) {
            hashOperations.put("sales", "daySales", "0");
        }

        //周同比
        Boolean weekRatioAbsent = hashOperations.putIfAbsent("sales", "weekRatio", weekRatio.toString());
        if (weekRatioAbsent.equals(Boolean.FALSE)) {
            hashOperations.put("sales", "weekRatio", weekRatio.toString());
        }

        //日同比
        Boolean dayRatioAbsent = hashOperations.putIfAbsent("sales", "dayRatio", dayRatio.toString());
        if (dayRatioAbsent.equals(Boolean.FALSE)) {
            hashOperations.put("sales", "dayRatio", dayRatio.toString());
        }

        //日均销售额
        Boolean averageSalesAbsent = hashOperations.putIfAbsent("sales", "averageSales", averageSales.toString());
        if (averageSalesAbsent.equals(Boolean.FALSE)) {
            hashOperations.put("sales", "averageSales", averageSales.toString());
        }

    }


    /**
     * 会员处理
     *
     * @param dateTimeFormatter 时间格式
     * @param totalDays         总天数
     */
    private void mebHandle(DateTimeFormatter dateTimeFormatter, BigDecimal totalDays) {

        List<MemberEntity> memberList = memberService.list();
        LocalDate now = LocalDate.now();
        LocalDate thisWeekMonday = now.minusWeeks(1).with(DayOfWeek.MONDAY);
        LocalDate thisWeekSunday = now.minusWeeks(1).with(DayOfWeek.SUNDAY);

        LocalDate monday = now.minusWeeks(2).with(DayOfWeek.MONDAY);
        LocalDate sunday = now.minusWeeks(2).with(DayOfWeek.SUNDAY);

        //总会员数
        BigDecimal totalMembers = BigDecimal.valueOf(memberList.size());

        //上上周注册会员总数
        long totalMembersLastWeek = memberList.stream()
                .filter(item -> {
                    final String createTime = item.getCreateTime();
                    LocalDateTime parsedDateTime = LocalDateTime.parse(createTime, dateTimeFormatter);
                    LocalDate date = parsedDateTime.toLocalDate();
                    return date.isAfter(monday) && date.isBefore(sunday);
                }).count();

        //上周注册会员总数
        long totalMembersThisWeek = memberList.stream().filter(item -> {
            final String createTime = item.getCreateTime();
            LocalDateTime parsedDateTime = LocalDateTime.parse(createTime, dateTimeFormatter);
            LocalDate date = parsedDateTime.toLocalDate();
            return date.isAfter(thisWeekMonday) && date.isBefore(thisWeekSunday);
        }).count();

        //周同比
        BigDecimal divideOfWeek = BigDecimal.valueOf(0L);
        if (totalMembersLastWeek != 0) {
            BigDecimal thisWeek = BigDecimal.valueOf(totalMembersThisWeek);
            BigDecimal lastWeek = BigDecimal.valueOf(totalMembersLastWeek);
            divideOfWeek = thisWeek.subtract(lastWeek).divide(lastWeek, 2)
                    .multiply(BigDecimal.valueOf(100L));
        }
        //昨日注册会员数
        long membersThisDay = memberList.stream().filter(item -> {
            final String createTime = item.getCreateTime();
            LocalDateTime parsedDateTime = LocalDateTime.parse(createTime, dateTimeFormatter);
            return parsedDateTime.toLocalDate().isEqual(now.plusDays(-1));
        }).count();

        //前日注册会员数
        long membersLastDay = memberList.stream().filter(item -> {
            final String createTime = item.getCreateTime();
            LocalDateTime parsedDateTime = LocalDateTime.parse(createTime, dateTimeFormatter);
            return parsedDateTime.toLocalDate().isEqual(LocalDate.now().plusDays(-2));
        }).count();

        //日同比
        BigDecimal divideOfDay = BigDecimal.valueOf(0L);
        if (membersLastDay != 0L) {
            BigDecimal thisDay = BigDecimal.valueOf(membersThisDay);
            BigDecimal lastDay = BigDecimal.valueOf(membersLastDay);
            divideOfDay = thisDay.subtract(lastDay).divide(lastDay, 2)
                    .multiply(BigDecimal.valueOf(100L));
        }

        //日均注册会员数
        BigDecimal averageMember = totalMembers.divide(totalDays, 0, BigDecimal.ROUND_HALF_UP);

        //总会员数
        Boolean totalMembersAbsent = hashOperations.putIfAbsent("member", "totalMembers", totalMembers.toString());
        if (totalMembersAbsent.equals(Boolean.FALSE)) {
            hashOperations.put("member", "totalMembers", totalMembers.toString());
        }

        //周同比
        Boolean divideOfWeekAbsent = hashOperations.putIfAbsent("member", "divideOfWeek", divideOfWeek.toString());
        if (divideOfWeekAbsent.equals(Boolean.FALSE)) {
            hashOperations.put("member", "divideOfWeek", divideOfWeek.toString());
        }

        //日同比
        Boolean divideOfDayAbsent = hashOperations.putIfAbsent("member", "divideOfDay", divideOfDay.toString());
        if (divideOfDayAbsent.equals(Boolean.FALSE)) {
            hashOperations.put("member", "divideOfDay", divideOfDay.toString());
        }

        //日均注册会员数
        Boolean averageAbsent = hashOperations.putIfAbsent("member", "averageMember", averageMember.toString());
        if (averageAbsent.equals(Boolean.FALSE)) {
            hashOperations.put("member", "averageMember", averageMember.toString());
        }


    }
}
